from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import HTTPException, status, Request, Depends
from sqlalchemy.orm import Session
import database
import schemas
import os

# 配置
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-change-this-in-production")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24  # 24小时

# 密码加密
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -> str:
    """获取密码哈希"""
    return pwd_context.hash(password)

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    """创建访问令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def verify_token(token: str) -> Optional[schemas.TokenData]:
    """验证令牌并返回用户信息"""
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        role: str = payload.get("role", "user")
        if username is None:
            return None
        return schemas.TokenData(username=username, role=role)
    except JWTError:
        return None

def authenticate_user(db: Session, username: str, password: str, request: Request = None) -> Optional[database.User]:
    """验证用户并记录登录"""
    user = db.query(database.User).filter(database.User.username == username).first()
    
    # 记录登录尝试
    login_record = database.LoginRecord(
        user_id=user.id if user else None,
        ip_address=get_client_ip(request) if request else None,
        user_agent=request.headers.get("user-agent") if request else None,
        status="success" if user and verify_password(password, user.hashed_password) else "failed"
    )
    
    if not user:
        # 即使用户不存在也要记录失败的登录尝试
        db.add(login_record)
        db.commit()
        return None
    
    if not verify_password(password, user.hashed_password):
        db.add(login_record)
        db.commit()
        return None
    
    # 登录成功，记录登录
    db.add(login_record)
    db.commit()
    return user

def get_client_ip(request: Request) -> str:
    """获取客户端IP地址"""
    if not request:
        return None
    
    # 检查是否有代理转发的IP
    forwarded_for = request.headers.get("X-Forwarded-For")
    if forwarded_for:
        return forwarded_for.split(",")[0].strip()
    
    real_ip = request.headers.get("X-Real-IP")
    if real_ip:
        return real_ip
    
    return request.client.host if request.client else None

def get_user_by_username(db: Session, username: str) -> Optional[database.User]:
    """根据用户名获取用户"""
    return db.query(database.User).filter(database.User.username == username).first()

def get_user_by_email(db: Session, email: str) -> Optional[database.User]:
    """根据邮箱获取用户"""
    return db.query(database.User).filter(database.User.email == email).first()

def create_user(db: Session, user: schemas.UserCreate) -> database.User:
    """创建新用户"""
    # 检查用户名是否已存在
    if get_user_by_username(db, user.username):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户名已存在"
        )
    
    # 检查邮箱是否已存在
    if get_user_by_email(db, user.email):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="邮箱已被注册"
        )
    
    # 创建新用户
    hashed_password = get_password_hash(user.password)
    db_user = database.User(
        username=user.username,
        email=user.email,
        phone=user.phone,
        hospital=user.hospital,
        position=user.position,
        hashed_password=hashed_password,
        role=user.role
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

def require_admin(current_user: database.User) -> database.User:
    """要求管理员权限"""
    if current_user.role != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="需要管理员权限"
        )
    return current_user

def record_data_processing(
    db: Session, 
    user_id: int, 
    operation_type: str, 
    operation_details: str = None,
    file_name: str = None,
    duration_ms: int = None,
    status: str = "success",
    error_message: str = None
) -> database.DataProcessingRecord:
    """记录数据处理操作"""
    record = database.DataProcessingRecord(
        user_id=user_id,
        operation_type=operation_type,
        operation_details=operation_details,
        file_name=file_name,
        duration_ms=duration_ms,
        status=status,
        error_message=error_message
    )
    db.add(record)
    db.commit()
    db.refresh(record)
    return record 